import React, { Component ,createRef} from 'react'
import './cropper.scss'

const mousePosition = {
  startX:0,
  startY:0,
  endX:0,
  endY:0,
  startL:0,
  startT:0,
  startW:0,
  startH:0,
  setStartDomLTWH:function(l,t,w,h){
    this.startL = l
    this.startT = t
    this.startW = w
    this.startH = h
  },
  setStartMousePosition:function(x,y){
    this.startX = x
    this.startY = y
  },
  setEndMousePosition:function(x,y){
    this.endX = x
    this.endY = y
  },
  getPositionXY:function(){
    let x = this.endX - this.startX,
    y = this.endY - this.startY
    return {
      x,
      y,
      l:this.startL + x,
      t:this.startT + y,
    }
  },
  getPositionStartState:function(){
    let x = this.endX - this.startX,
    y = this.endY - this.startY
    return {
      x,
      y,
      l:this.startL,
      t:this.startT,
      w:this.startW,
      h:this.startH
    }
  },
  getPosition:function(){
    let l = Math.min(this.startX,this.endX),
    t = Math.min(this.startY,this.endY),
    r = Math.max(this.startX,this.endX),
    b = Math.max(this.startY,this.endY),
    h = b - t,
    w = r - l
    return {
      t,
      l,
      w,
      h
    }
  }
}

const clickState = {
  isCropperBox:false,
  isCropperBoxSetPosition:false,
  cropperBoxSetPositionState:null
}

const setImgWH = (w,h,iw,ih)=>{
  let width,height,scale
  if(w/h < iw/ih){
    scale = w / iw
    height = ih * scale
    width = w
  }else{
    scale = h / ih
    width = iw * scale
    height = h 
  }
  return {
    width,
    height,
    scale
  }
}
class CropperDemo extends Component {
  constructor(){
    super()
    this.canvas = document.createElement('canvas')
    this.ctx = this.canvas.getContext('2d')
    this.imageRef = createRef()
  }
  state = {
    bw:600,
    bh:600,
    t:100,
    l:100,
    w:100,
    h:100,
    isCropper:false,
    isMoveStart:false,
    imgUrl:null,
    img:{
      src:null,
      width:0,
      height:0,
      scale:1
    },
  }
  mdHandle = (e)=>{
    mousePosition.setStartMousePosition(e.nativeEvent.pageX,e.nativeEvent.pageY)
    mousePosition.setStartDomLTWH(this.state.l,this.state.t,this.state.w,this.state.h)
    if(e.target.getAttribute('class') == 'cropper-box'){
      clickState.isCropperBox = true
    }else if(e.target.getAttribute('class') == 'cropper-box-set-position'){
      clickState.isCropperBoxSetPosition = true
      clickState.cropperBoxSetPositionState = e.target.getAttribute('data-state')
    }
    this.setState({
      isCropper:true,
      isMoveStart:true
    })
  }
  mmHandle = (e)=>{
    if(this.state.isMoveStart){
      mousePosition.setEndMousePosition(e.nativeEvent.pageX,e.nativeEvent.pageY)
      if(clickState.isCropperBox){
        let mpLT = mousePosition.getPositionXY()
        this.setState({
          l:mpLT.l,
          t:mpLT.t
        },this.drawImage)
      }else if(clickState.isCropperBoxSetPosition){
        let mpState = mousePosition.getPositionStartState()
        let cropperState = {
          l:mpState.l,
          t:mpState.t,
          h:mpState.h,
          w:mpState.w
        }
        if(clickState.cropperBoxSetPositionState.indexOf('l') >= 0){
          let lw = mpState.w - mpState.x
          cropperState.w = Math.abs(lw)
          if(lw < 0){
            cropperState.l = mpState.l + mpState.w
          }else{
            cropperState.l = mpState.l + mpState.x
          }
        }
        if(clickState.cropperBoxSetPositionState.indexOf('t') >= 0){
          let th = mpState.h - mpState.y
          cropperState.h = Math.abs(th)
          if(th < 0){
            cropperState.t = mpState.t + mpState.h
          }else{
            cropperState.t = mpState.t + mpState.y
          }
        }
        if(clickState.cropperBoxSetPositionState.indexOf('r') >= 0){
          let rw = mpState.w + mpState.x
          cropperState.w = Math.abs(rw)
          if(rw < 0){
            cropperState.l = mpState.l - Math.abs(rw)
          }
        }
        if(clickState.cropperBoxSetPositionState.indexOf('b') >= 0){
          let bh = mpState.h + mpState.y
          cropperState.h = Math.abs(bh)
          if(bh < 0){
            cropperState.t = mpState.t - Math.abs(bh)
          }
        }
        this.setState({
          ...cropperState
        },this.drawImage)
      }else{
        this.setState({
          ...mousePosition.getPosition()
        },this.drawImage)
      }
    }
  }
  muHandle = (e)=>{
    if(this.state.isMoveStart){
      mousePosition.setEndMousePosition(e.nativeEvent.pageX,e.nativeEvent.pageY)
      if(clickState.isCropperBox){
        this.setState({
          isMoveStart:false
        })
      }else if(clickState.isCropperBoxSetPosition){
        this.setState({
          isMoveStart:false
        })
      }else{
        let mouseState = mousePosition.getPosition()
        this.setState({
          isMoveStart:false,
          isCropper:mouseState.h > 0 && mouseState.w > 0,
          ...mouseState
        },this.drawImage) 
      }
      clickState.isCropperBox = false
      clickState.isCropperBoxSetPosition = false
    }
  }
  drawImage = (()=>{
    let timeID = 0
    return ()=>{
      clearTimeout(timeID)
      timeID = setTimeout(()=>{
        let {ctx,state,canvas} = this
        let {l,t,w,h,img} = state
        canvas.width = w
        canvas.height = h
        ctx.drawImage(this.imageRef.current,l/img.scale,t/img.scale,w/img.scale,h/img.scale,0,0,w,h)
        this.setState({
          imgUrl:canvas.toDataURL()
        })
      },50)
    }
  })()
  setFile = (e)=>{
    let file = URL.createObjectURL(e.target.files[0]),
    img = document.createElement('img')
    img.src = file
    img.onload = ()=>{
      this.setState({
        img:{
          src:file,
          ...setImgWH(this.state.bw,this.state.bh,img.width,img.height)
        }
      })  
    }
    
    
  }
  render() {
    return (
      <div>
        <div className="box" style={{width:this.state.bw,height:this.state.bh}} onMouseDown={this.mdHandle} onMouseUp={this.muHandle} onMouseMove={this.mmHandle}>
        <img className="img" ref={this.imageRef} src={this.state.img.src} style={{height:this.state.img.height,width:this.state.img.width}}/>
          {
            this.state.isCropper && 
            <div className="shadow-box">
              <div className="shadow" style={{
                top:0,
                left:0,
                height:'100%',
                width:this.state.l
              }}/>
              <div className="shadow" style={{
                top:0,
                right:0,
                height:'100%',
                width:this.state.bw - this.state.w - this.state.l
              }}/>
              <div className="shadow" style={{
                top:0,
                left:this.state.l,
                height:this.state.t,
                width:this.state.w
              }}/>
              <div className="shadow" style={{
                bottom:0,
                left:this.state.l,
                height:this.state.bh - this.state.t - this.state.h,
                width:this.state.w
              }}/>
              <div className="cropper-box" style={{
                top:this.state.t,
                left:this.state.l,
                width:this.state.w,
                height:this.state.h,
              }}>
                <div className="cropper-box-set-position" style={{top:-4,left:-4}} data-state={'lt'}/>
                <div className="cropper-box-set-position" style={{top:-4,right:-4}} data-state={'tr'}/>
                <div className="cropper-box-set-position" style={{bottom:-4,right:-4}} data-state={'br'}/>
                <div className="cropper-box-set-position" style={{bottom:-4,left:-4}} data-state={'lb'}/>
                <div className="cropper-box-set-position" style={{top:-4,left:'calc(50% - 4px)'}} data-state={'t'}/>
                <div className="cropper-box-set-position" style={{left:-4,top:'calc(50% - 4px)'}} data-state={'l'}/>
                <div className="cropper-box-set-position" style={{right:-4,top:'calc(50% - 4px)'}} data-state={'r'}/>
                <div className="cropper-box-set-position" style={{bottom:-4,right:'calc(50% - 4px)'}} data-state={'b'}/>
              </div>
            </div>
          }
        </div>
        <div>
          <input type='file' onChange={this.setFile}/>
        </div>
        <img src={this.state.imgUrl}/>
      </div>
    )
  }
}

export default CropperDemo;
